<template>
  <el-form
    ref="formRef"
    :model="formData"
    :rules="formRules"
    :label-width="labelWidth"
    :label-position="labelPosition"
    :size="size"
    :disabled="disabled"
    @submit.prevent="handleSubmit"
    class="secure-form"
  >
    <slot :form-data="formData" :validate="validateForm" :reset="resetForm" />
    
    <!-- 提交按钮 -->
    <el-form-item v-if="showSubmitButton">
      <el-button
        type="primary"
        :loading="submitting"
        :disabled="disabled"
        @click="handleSubmit"
      >
        {{ submitText }}
      </el-button>
      <el-button v-if="showResetButton" @click="resetForm">
        {{ resetText }}
      </el-button>
    </el-form-item>
  </el-form>
</template>

<script setup>
import { ref, reactive, computed, watch } from 'vue'
import { ElMessage } from 'element-plus'
import { InputValidator, XSSProtection, SecurityUtils } from '../utils/security'

const props = defineProps({
  // 表单数据
  modelValue: {
    type: Object,
    default: () => ({})
  },
  // 验证规则
  rules: {
    type: Object,
    default: () => ({})
  },
  // 表单配置
  labelWidth: {
    type: String,
    default: '100px'
  },
  labelPosition: {
    type: String,
    default: 'right'
  },
  size: {
    type: String,
    default: 'default'
  },
  disabled: {
    type: Boolean,
    default: false
  },
  // 按钮配置
  showSubmitButton: {
    type: Boolean,
    default: true
  },
  showResetButton: {
    type: Boolean,
    default: true
  },
  submitText: {
    type: String,
    default: '提交'
  },
  resetText: {
    type: String,
    default: '重置'
  },
  // 安全配置
  enableXSSProtection: {
    type: Boolean,
    default: true
  },
  autoSanitize: {
    type: Boolean,
    default: true
  },
  sanitizeOptions: {
    type: Object,
    default: () => ({})
  },
  // 防重复提交
  preventDuplicateSubmit: {
    type: Boolean,
    default: true
  },
  submitDelay: {
    type: Number,
    default: 1000
  }
})

const emit = defineEmits(['update:modelValue', 'submit', 'reset', 'validate'])

const formRef = ref()
const submitting = ref(false)
const lastSubmitTime = ref(0)

// 表单数据
const formData = computed({
  get: () => props.modelValue,
  set: (value) => {
    // 自动清理输入
    if (props.enableXSSProtection && props.autoSanitize) {
      const sanitizedValue = sanitizeFormData(value)
      emit('update:modelValue', sanitizedValue)
    } else {
      emit('update:modelValue', value)
    }
  }
})

// 表单验证规则
const formRules = computed(() => {
  const rules = { ...props.rules }
  
  // 为每个字段添加XSS检测
  if (props.enableXSSProtection) {
    Object.keys(rules).forEach(field => {
      if (!rules[field]) rules[field] = []
      
      // 添加XSS检测规则
      rules[field].unshift({
        validator: (rule, value, callback) => {
          if (value && XSSProtection.detectXSS(value)) {
            callback(new Error('输入内容包含不安全字符，请检查后重新输入'))
          } else {
            callback()
          }
        },
        trigger: 'blur'
      })
    })
  }
  
  return rules
})

/**
 * 清理表单数据
 */
function sanitizeFormData(data) {
  // 如果data不是对象，直接返回
  if (!data || typeof data !== 'object') {
    return data
  }
  
  const sanitized = {}
  
  Object.keys(data).forEach(key => {
    const value = data[key]
    
    if (typeof value === 'string') {
      // 确保字符串值经过清理后仍然是字符串
      const cleanedValue = XSSProtection.sanitizeInput(value, props.sanitizeOptions)
      sanitized[key] = typeof cleanedValue === 'string' ? cleanedValue : value
    } else if (Array.isArray(value)) {
      // 只有当原始值确实是数组时才进行数组处理
      sanitized[key] = value.map(item => 
        typeof item === 'string' 
          ? XSSProtection.sanitizeInput(item, props.sanitizeOptions)
          : item
      )
    } else {
      // 对于其他类型（boolean、number等），直接保持原值
      sanitized[key] = value
    }
  })
  
  return sanitized
}

/**
 * 验证表单
 */
function validateForm() {
  return new Promise((resolve, reject) => {
    if (!formRef.value) {
      reject(new Error('表单引用不存在'))
      return
    }
    
    formRef.value.validate((valid, fields) => {
      emit('validate', { valid, fields })
      
      if (valid) {
        resolve(true)
      } else {
        // 显示第一个错误信息
        const firstField = Object.keys(fields)[0]
        const firstError = fields[firstField][0]
        ElMessage.error(firstError.message)
        console.error('表单验证失败:', fields)
        reject(fields)
      }
    })
  })
}

/**
 * 重置表单
 */
function resetForm() {
  formRef.value.resetFields()
  emit('reset')
}

/**
 * 处理表单提交
 */
const handleSubmit = SecurityUtils.debounce(async () => {
  // 防重复提交检查
  if (props.preventDuplicateSubmit) {
    const now = Date.now()
    if (now - lastSubmitTime.value < props.submitDelay) {
      ElMessage.warning('请勿重复提交')
      return
    }
    lastSubmitTime.value = now
  }
  
  try {
    submitting.value = true
    
    // 验证表单
    await validateForm()
    
    // 最终清理数据
    let submitData = { ...formData.value }
    if (props.enableXSSProtection) {
      submitData = sanitizeFormData(submitData)
    }
    
    // 触发提交事件
    emit('submit', submitData)
    
  } catch (error) {
    console.error('表单提交失败:', error)
  } finally {
    submitting.value = false
  }
}, 300)

/**
 * 验证单个字段
 */
function validateField(field) {
  return new Promise((resolve, reject) => {
    formRef.value.validateField(field, (errorMessage) => {
      if (errorMessage) {
        reject(errorMessage)
      } else {
        resolve(true)
      }
    })
  })
}

/**
 * 清除字段验证
 */
function clearValidation(fields) {
  formRef.value.clearValidate(fields)
}

// 暴露方法给父组件
defineExpose({
  validate: validateForm,
  validateField,
  resetFields: resetForm,
  clearValidate: clearValidation,
  sanitizeData: sanitizeFormData,
  handleSubmit
})
</script>

<style scoped>
.secure-form {
  max-width: 600px;
}

.secure-form :deep(.el-form-item__error) {
  color: #f56c6c;
  font-size: 12px;
  line-height: 1;
  padding-top: 4px;
  position: absolute;
  top: 100%;
  left: 0;
}

.secure-form :deep(.el-form-item) {
  margin-bottom: 22px;
  position: relative;
}

.secure-form :deep(.el-input__inner),
.secure-form :deep(.el-textarea__inner) {
  transition: border-color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
}

.secure-form :deep(.el-input__inner:focus),
.secure-form :deep(.el-textarea__inner:focus) {
  border-color: #409eff;
  outline: 0;
  box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.2);
}

.secure-form :deep(.el-form-item.is-error .el-input__inner),
.secure-form :deep(.el-form-item.is-error .el-textarea__inner) {
  border-color: #f56c6c;
}

.secure-form :deep(.el-form-item.is-error .el-input__inner:focus),
.secure-form :deep(.el-form-item.is-error .el-textarea__inner:focus) {
  box-shadow: 0 0 0 2px rgba(245, 108, 108, 0.2);
}
</style>